/**
 * 
 */
package ptvv.system;

import java.util.Vector;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 
 * @author dkz
 * 
 */
public abstract class DefPortAutomaton extends Thread {
	protected BlockingQueue<String> eventQueue = new LinkedBlockingQueue<String>(); // start/end
	protected Vector<InputPort> inputPorts = new Vector<InputPort>(); // input
	protected Vector<OutputPort> outputPorts = new Vector<OutputPort>(); // output

	protected String message;
	protected boolean repeatBool = false;
	protected Trace logger = Trace.getLogger();
	protected InternalStates internalState = InternalStates.Starting;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

	public void addOutputPort() {
		// outputPorts
		outputPorts.add(new OutputPort());
	}

	public void addInputPort() {
		// outputPorts
		inputPorts.add(new InputPort());
	}

	public void setInputPort(int portNum) {
		if (portNum > inputPorts.size())
			System.out.println("BAD");
		else if (portNum == inputPorts.size())
			inputPorts.add(new InputPort());
		else if (portNum < inputPorts.size())
			System.out.println("Already Added");

	}

	public void setOutputPort(ThreadAndClass temp, int portNumber, int dest) {
		// outputPorts
		if (portNumber == outputPorts.size()) {// need to make
			// OutputPort top = new OutputPort();
			// top.setProperties(temp, dest);
			outputPorts.add(new OutputPort(temp, dest));

			// System.out.println(this.getName() + "adding");
		} else if (portNumber > outputPorts.size()) {
			// System.out.println(this.getName());
			System.out.println("HOUSTON we have a problem " + "portNum: "
					+ portNumber + " size: " + outputPorts.size());

		} else if (portNumber < outputPorts.size()) {
			// System.out.println(" pN: " + portNumber + "outputPorts size:"
			// + outputPorts.size());
			outputPorts.get(portNumber).setProperties(temp, dest);
			// System.out.println("setting");
		}
	}

	public InternalStates getInternalState() {
		return internalState;
	}

	public void runStates() {
		try {
			switch (internalState) {
			case Starting:
				starting();
				this.internalState = InternalStates.Ready;
				break;
			case Ready:
				ready();
				this.internalState = InternalStates.Running;
				break;
			case Running:
				running();
				this.internalState = InternalStates.End;
				break;
			case Suspended: // not used
				suspended();
				this.internalState = InternalStates.Running;
				break;
			case End:
				end();
				this.internalState = InternalStates.Dead;
				break;
			case Dead:
				dead();
				this.internalState = InternalStates.ReallyDead;

			}
			if (repeatBool) {
				this.internalState = InternalStates.Starting;
				repeatBool = false;
			}

		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// logger.log(this.getName() + ": " + internalState.toString());

	}

	public abstract void starting() throws InterruptedException;

	public abstract void ready() throws InterruptedException;

	public abstract void running() throws InterruptedException;

	public abstract void suspended() throws InterruptedException;

	public abstract void end() throws InterruptedException;

	public abstract void dead() throws InterruptedException;

	public void addEvent(String str) {
		// System.out.println("Start Received");

		try {
			eventQueue.put(str);
		} catch (InterruptedException iex) {
			Thread.currentThread().interrupt();
			throw new RuntimeException(
					"Unexpected interruption while adding event");
		}
	}

	public void addInput(String str) {
		// System.out.println("Input Received");
		if (inputPorts.size() == 0)
			inputPorts.add(new InputPort());
		try {
			inputPorts.get(0).queue.put(str);
		} catch (InterruptedException iex) {
			Thread.currentThread().interrupt();
			throw new RuntimeException("Unexpected interruption");
		}
	}

	public void addInput(String str, int portnum) {

		try {
			// System.out.println(this.getName());
			inputPorts.get(portnum).queue.put(str);
		} catch (InterruptedException iex) {
			Thread.currentThread().interrupt();
			throw new RuntimeException("Unexpected interruption");
		}
	}

	public void run() {
		while (internalState != InternalStates.ReallyDead)
			runStates();
	}
}
